package config

// package config 提供配置文件的编解码功能，支持json、xml、yaml、toml等多种格式，
// 通过函数式选项模式配置编解码器的上下文、数据源、编码/解码/扫描逻辑

import (
	"context"                  // 提供上下文功能，用于控制操作的生命周期
	"gameServer/encoding/json" // 自定义json编码包，提供Marshal/Unmarshal方法
	"gameServer/encoding/toml" // 自定义toml编码包，提供Marshal/Unmarshal方法
	"gameServer/encoding/xml"  // 自定义xml编码包，提供Marshal/Unmarshal方法
	"gameServer/encoding/yaml" // 自定义yaml编码包，提供Marshal/Unmarshal方法
	"gameServer/errors"        // 自定义错误包，包含无效格式等错误定义
	"strings"                  // 提供字符串处理函数，此处用于格式名称大小写转换
)

/* 配置编解码器 */

// 编解码器接口定义

// Codec 函数类型，用于配置codec结构体的选项
// 接收*codec作为参数，通过闭包修改codec的字段，实现函数式选项配置
type Codec func(c *codec)

// Encoder 编码器函数类型，用于将内容按指定格式编码为字节切片
// 参数：
//   - format: 编码格式（如"json"、"yaml"等）
//   - content: 待编码的内容（任意类型）
//
// 返回：编码后的字节切片和可能的错误
type Encoder func(format string, content interface{}) ([]byte, error)

// Decoder 解码器函数类型，用于将字节切片按指定格式解码为interface{}
// 参数：
//   - format: 解码格式（如"json"、"yaml"等）
//   - content: 待解码的字节切片
//
// 返回：解码后的对象和可能的错误
type Decoder func(format string, content []byte) (interface{}, error)

// Scanner 扫描器函数类型，用于将字节切片按指定格式解析到目标对象
// 参数：
//   - format: 解析格式（如"json"、"yaml"等）
//   - content: 待解析的字节切片
//   - dest: 目标对象（需为指针类型，用于接收解析结果）
//
// 返回：可能的错误
type Scanner func(format string, content []byte, dest interface{}) error

// codec 编解码器核心结构体，存储编解码所需的上下文、数据源和处理函数
type codec struct {
	ctx     context.Context // 上下文，用于传递超时、取消信号等
	sources []ConfigSource  // 配置源列表，Source为提供配置内容的接口（未在此处定义）
	encoder Encoder         // 编码器实例，用于执行编码操作
	decoder Decoder         // 解码器实例，用于执行解码操作
	scanner Scanner         // 扫描器实例，用于执行解析到目标对象的操作
}

// 默认编码器，暂无配置源
func defaultCodec() *codec {
	return &codec{
		ctx:     context.Background(),
		encoder: defaultEncoder,
		decoder: defaultDecoder,
		scanner: defaultScanner,
	}
}

// SetContext 配置codec的上下文选项
// 参数：ctx - 待设置的上下文
// 返回：Codec函数，用于修改codec的ctx字段
func SetContext(ctx context.Context) Codec {
	return func(c *codec) { c.ctx = ctx }
}

// SetSources 配置codec的数据源选项
// 参数：sources - 待设置的数据源列表（可变参数）
// 返回：Codec函数，用于修改codec的sources字段
func SetSources(sources ...ConfigSource) Codec {
	return func(c *codec) { c.sources = sources[:] } // 拷贝切片避免外部修改影响内部
}

// SetEncoder 配置codec的编码器选项
// 参数：encoder - 待设置的编码器
// 返回：Codec函数，用于修改codec的encoder字段
func SetEncoder(encoder Encoder) Codec {
	return func(c *codec) { c.encoder = encoder }
}

// SetDecoder 配置codec的解码器选项
// 参数：decoder - 待设置的解码器
// 返回：Codec函数，用于修改codec的decoder字段
func SetDecoder(decoder Decoder) Codec {
	return func(c *codec) { c.decoder = decoder }
}

// defaultEncoder 默认编码器实现，支持json、xml、yaml、toml格式
// 根据输入的format（忽略大小写）选择对应的编码方法
func defaultEncoder(format string, content interface{}) ([]byte, error) {
	switch strings.ToLower(format) { // 统一转为小写，避免格式名称大小写问题
	case json.Name: // 若格式为json，使用json包的Marshal
		return json.Marshal(content)
	case xml.Name: // 若格式为xml，使用xml包的Marshal
		return xml.Marshal(content)
	case yaml.Name, yaml.ShortName: // 若格式为yaml（支持全名和简称），使用yaml包的Marshal
		return yaml.Marshal(content)
	case toml.Name: // 若格式为toml，使用toml包的Marshal
		return toml.Marshal(content)
	default: // 不支持的格式，返回无效格式错误
		return nil, errors.ErrInvalidFormat
	}
}

// defaultDecoder 默认解码器实现，支持json、xml、yaml、toml格式
// 根据输入的format（忽略大小写）选择对应的解码方法，通过unmarshal辅助函数处理解码逻辑
func defaultDecoder(format string, content []byte) (interface{}, error) {
	switch strings.ToLower(format) { // 统一转为小写处理
	case json.Name: // json格式解码
		return unmarshal(content, json.Unmarshal)
	case xml.Name: // xml格式解码
		return unmarshal(content, xml.Unmarshal)
	case yaml.Name, yaml.ShortName: // yaml格式解码
		return unmarshal(content, yaml.Unmarshal)
	case toml.Name: // toml格式解码
		return unmarshal(content, toml.Unmarshal)
	default: // 不支持的格式，返回无效格式错误
		return nil, errors.ErrInvalidFormat
	}
}

// defaultScanner 默认扫描器实现，支持json、xml、yaml、toml格式
// 直接将内容解析到目标对象（dest需为指针），与decoder的区别是不返回新对象而是修改目标对象
func defaultScanner(format string, content []byte, dest interface{}) error {
	switch strings.ToLower(format) { // 统一转为小写处理
	case json.Name: // json格式解析到dest
		return json.Unmarshal(content, dest)
	case xml.Name: // xml格式解析到dest
		return xml.Unmarshal(content, dest)
	case yaml.Name, yaml.ShortName: // yaml格式解析到dest
		return yaml.Unmarshal(content, dest)
	case toml.Name: // toml格式解析到dest
		return toml.Unmarshal(content, dest)
	default: // 不支持的格式，返回无效格式错误
		return errors.ErrInvalidFormat
	}
}

// unmarshal 解码辅助函数，尝试将内容解析为map或切片
// 先尝试解析为map[string]interface{}，失败则尝试解析为[]interface{}
// 参数：
//   - content: 待解码的字节切片
//   - decodeUnmarshal: 具体的解码函数（如json.Unmarshal）
//
// 返回：解析后的对象（map或切片）和可能的错误
func unmarshal(content []byte, decodeUnmarshal func(data []byte, v interface{}) error) (dest interface{}, err error) {
	//当 JSON 数据是对象（{key: value, ...}）时：要求v必须是 *map[string]T（T为具体类型，如interface{}、string等）或结构体指针
	//当 JSON 数据是数组（[value1, value2, ...]）时：要求v必须是 *[]T（T为具体类型）。
	dest = make(map[string]interface{})                    // 初始化map作为第一个尝试的目标类型
	if err = decodeUnmarshal(content, &dest); err == nil { // 若解析map成功，直接返回
		return
	}

	dest = make([]interface{}, 0)         // 若map解析失败，初始化切片作为第二个尝试的目标类型
	err = decodeUnmarshal(content, &dest) // 尝试解析为切片，返回结果（无论成功与否）
	return
}
